home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_1 / cpdist / filecopy.c < prev    next >
C/C++ Source or Header  |  1994-01-12  |  7KB  |  297 lines

  1. /*
  2.  *  FILECOPY.C
  3.  *
  4.  *  (c)Copyright 1990,93 by Tobias Ferber,  All Rights Reserved.
  5.  */
  6.  
  7. #include "filecopy.h"
  8. #include <stdio.h>
  9.  
  10. #ifdef AMIGA
  11. #include <exec/types.h>
  12. #include <exec/memory.h>
  13. #endif /* AMIGA */
  14.  
  15. /* private statics */
  16. static uchar *copybuffer= (uchar *)0L;
  17. static ulong buffersize= 0L;
  18.  
  19. static char rcs_id[]= "$Id: filecopy.c 1.2 93/09/19 21:33:11 tf Exp $";
  20.  
  21. /*
  22.  *
  23.  * FUNCTION
  24.  *
  25.  *   fc_setbuf -- allocate or free a copy buffer for filecopy()
  26.  *
  27.  * SYNOPSIS
  28.  *   #include "filecopy.h"
  29.  *
  30.  *   result= fc_setbuf(numbytes)
  31.  *   ulong result;
  32.  *   ulong numbytes;
  33.  *
  34.  * DESCRIPTION
  35.  *
  36.  *   This function tries to allocate 'numbytes' bytes for the local
  37.  *   copy buffer.  If you pass 0L with the 'numbytes' parameter the
  38.  *   actual copy buffer will be free()d.
  39.  *   The current size of the copy buffer will be returned.
  40.  *
  41.  * NOTE
  42.  *
  43.  *   It is absolutely legal to re-size your copy buffer by calling this
  44.  *   function only once (with your new buffer size) instead of calling
  45.  *   it twice (with numbytes==0L first)
  46.  *   Note also that this function does *NOT* check whether 'numbytes'
  47.  *   is larger than the local limit. (see "filecopy.h")
  48.  *
  49.  * SEE ALSO
  50.  *
  51.  *   filecopy(), "filecopy.h"
  52.  *
  53.  */
  54.  
  55. ulong fc_setbuf(numbytes)
  56. ulong numbytes;
  57. {
  58. #ifdef AMIGA
  59.   if(copybuffer && buffersize)
  60.     FreeMem(copybuffer, buffersize);
  61.  
  62. #else /* !AMIGA */
  63.   if(copybuffer)
  64.     free(copybuffer);
  65.  
  66. #endif /* AMIGA */
  67.  
  68.   copybuffer= (uchar *)0L;
  69.   buffersize= 0L;
  70.  
  71.  
  72.   if(numbytes)
  73.   {
  74.  
  75. #ifdef AMIGA
  76.     copybuffer= (uchar *)AllocMem(numbytes*sizeof(uchar), MEMF_PUBLIC);
  77.  
  78. #else /* !AMIGA */
  79.     copybuffer= (uchar *)malloc(numbytes*sizeof(uchar));
  80.  
  81. #endif /* AMIGA */
  82.  
  83.     if(copybuffer)
  84.       buffersize= numbytes*sizeof(uchar);
  85.   }
  86.   return buffersize;
  87. }
  88.  
  89. /*
  90. */
  91.  
  92. #ifdef DEBUG
  93. /* My favorite way of reporting that we're alive: */
  94. static void turn(on)
  95. int on;
  96. {
  97.   static char bars[]= "|/-\\|/-\\";
  98.   static int b= 0;
  99.  
  100.   if(on)
  101.   {
  102.     fprintf(stderr,"%c\b",bars[b++]);
  103.  
  104.     if(b >= sizeof(bars)-1)
  105.       b= 0;
  106.   }
  107.   else fprintf(stderr," \b");
  108.  
  109.   fflush(stderr);
  110. }
  111.  
  112. #endif /* DEBUG */
  113.  
  114.  
  115. /*
  116.  *
  117.  * FUNCTION
  118.  *
  119.  *   filecopy -- copy n bytes of data from one file pointer to another
  120.  *
  121.  * SYNOPSIS
  122.  *   #include "filecopy.h"
  123.  *
  124.  *   result= filecopy(src, dst, n)
  125.  *   long result;
  126.  *   long n;
  127.  *   FILE *src, *dst;
  128.  *
  129.  * DESCRIPTION
  130.  *
  131.  *   This function tries to copy 'n' bytes from given source stream 'src'
  132.  *   to the destination 'dst'.
  133.  *   If 'n' is == 0 then filecopy() will compute this value assuming that
  134.  *   all data following the current position of 'src' is ment to be copied.
  135.  *   If a copy buffer has been allocated successfully via fc_setbuf() then
  136.  *   filecopy() will take advantage of of it.  On the other hand, if no
  137.  *   buffer was allocated it will do so on it's own and tries to get either
  138.  *   'n' or (if 'n' is too large) MAXIMUM_BUFFERSIZE bytes.  (See the notes
  139.  *   about this value in "filecopy.h".)
  140.  *   If the allocation fails then filecopy() will copy your data byte for
  141.  *   byte.  Normally the number of written bytes will be returned but
  142.  *
  143.  * NOTE
  144.  *
  145.  *   This function tries to be very careful concerning errors.  If an error
  146.  *   occurs it will exit immediately returning either -1L in case of a read
  147.  *   error in the 'src' file or -2L in case of a write error with the 'dst'
  148.  *   file pointer.
  149.  *   Also filecopy() will *NOT* print out anything, even not if there was
  150.  *   an error.  (There may of course be some output if your OS feels a need
  151.  *   to do so.) It's up to the caller to use perror() or sth. similar to
  152.  *   inform the user about what went wrong.
  153.  *
  154.  * NOTE ALSO
  155.  *
  156.  *   This function assumes 'src' not to be a tty; especially not if you pass
  157.  *   n=0 with the arguments.  In other words, filecopy() will fail if seeking
  158.  *   with 'src' is impossible.
  159.  *   You can however pass a value n<0 in order to force a byte for byte
  160.  *   transfer without seeking.
  161.  *
  162.  */
  163.  
  164. long filecopy(src, dst, n)
  165. long n;
  166. FILE *src, *dst;
  167. {
  168.   long result= 0L;     /* The value returned by this function:
  169.                         * if non-negative the #of bytes written,
  170.                         * -1 = read error,  -2 = write error */
  171.  
  172.   ulong remember= 0L;  /* #of bytes allocated by *this* function */
  173.   long bytesleft= 0L;  /* #of bytes left for copying */
  174.  
  175.   if(n==0)
  176.   {
  177.     /* Compute the #of bytes left for copying */
  178.  
  179. #ifdef BUGGY_FTELL
  180.     do {
  181.       (void)fgetc(src);
  182.       if(!feof(src))
  183.         ++bytesleft;
  184.     } while(!feof(src) || ferror(src))
  185.  
  186. #else /* ftell() works fine */
  187.     if( fseek(src,0L,2L) >= 0) /* 2 == OFFSET_END */
  188.       bytesleft= ftell(src);
  189.     else
  190.       result= -1L;
  191.  
  192. #endif /* BUGGY_FTELL */
  193.  
  194.     if(!ferror(src) && bytesleft>0)
  195.     { if(fseek(src,-bytesleft,1L) < 0) /* 1 == OFFSET_CURRENT */
  196.         result= -1L;
  197.     }
  198.     else result= -1L;
  199.   }
  200.   else /* n!=0 */
  201.     bytesleft= (n > 0) ? n : 0L;
  202.  
  203.  
  204.   if(!result)
  205.   {
  206.     long nbytes= 0L;
  207.  
  208.     if(!copybuffer && bytesleft>0)
  209.     {
  210.       remember= fc_setbuf( (bytesleft > MAXIMUM_BUFFERSIZE) ?
  211.         MAXIMUM_BUFFERSIZE : bytesleft );
  212.     }
  213.  
  214.     /* If the allocation failed (or if n was negative) then we'll copy
  215.      * the data byte for byte which of course is hyper slow ;)
  216.      */
  217.  
  218.     if(!copybuffer || buffersize < 2L)
  219.     {
  220.       uchar c;
  221.       int done= 0;
  222.  
  223.       do {
  224.         c= fgetc(src);
  225.         if(!feof(src))
  226.         { fputc(c,dst);
  227.           nbytes++;
  228.           if(n>0 && nbytes>=n)
  229.             done= 1;
  230. #ifdef DEBUG
  231.           turn(1);
  232. #endif /* DEBUG */
  233.         }
  234.       } while(!done && !feof(src) && !ferror(src) && !ferror(dst));
  235.  
  236.       /* This might change later when checking ferror(): */
  237.       result= nbytes;
  238.     }
  239.  
  240.     else /* use the buffer */
  241.     {
  242.       long psize;  /* packet size */
  243.  
  244.       do {
  245.         psize= (bytesleft > buffersize) ? buffersize : bytesleft;
  246.         bytesleft-= psize;
  247.  
  248.         /* I think it's a good idea to use fread() and fwrite() with
  249.          * psize packets of size 1 here instead of 1 packet of size psize
  250.          * because these functions return the number of *complete* packets
  251.          * that were read (or written).  This way we can also handle
  252.          * partial packets if needed. */
  253.  
  254.         nbytes= fread(copybuffer, 1L, psize, src);
  255.  
  256.         if(!ferror(src))
  257.         {
  258.           /* write exactly as many bytes as we read before */
  259.  
  260.           nbytes= fwrite(copybuffer, 1L, nbytes, dst);
  261.           result += nbytes;
  262.         }
  263.  
  264.         /* A partial read or written packet indicates that we're done,
  265.          * it does however not neccessarily mean that there was an error.
  266.          * Changing the result to a negative value can be done later
  267.          * by testing ferror(). */
  268.  
  269.         if(nbytes!=psize)
  270.           bytesleft= 0;
  271.  
  272. #ifdef DEBUG
  273.         turn(1);
  274. #endif
  275.  
  276.       } while(bytesleft>0 && !ferror(src) && !ferror(dst));
  277.     }
  278.  
  279.     if(ferror(src))
  280.       result= -1L;
  281.     else if(ferror(dst))
  282.       result= -2L;
  283.   }
  284.  
  285.   /* free the copy buffer if it was allocated by us */
  286.   if(remember)
  287.     fc_setbuf(0L);
  288.  
  289. #ifdef DEBUG
  290.   turn(0);
  291. #endif
  292.  
  293.   return result;
  294. }
  295.  
  296.  
  297.